// shared.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <pointers.h>
#include <hierarchical.h>
#include <vector>

#include <comdef.h>
using namespace marus;

FORCE_CLASS_POLICY(Hier, IS_REFCOUNTED)
FORCE_CLASS_POLICY(Me, IS_REFCOUNTED)

#include <string>

class   Hier : public refcounted<Hier>
             , public hierarchical<Hier>
{
protected:
    _STD string _name;
public:

    Hier(_STD string name_)
        : _name(name_)
    {
    }

    Hier(const _Ref& parent_, _STD string name_)
        : _name(name_)
    {
        if (parent_)
            parent_->append_child(this);
    }

    inline 
    bool    has_name(const _STD string& name_) const
    {
        return _name == name_;
    }

    struct _by_name
    {
        _STD string _name;
        _by_name(const _STD string& name_)
            : _name(name_)
        {}

        inline
        bool operator()(const _Ref& ref_) const
        {
            if (ref_)
                return ref_.get()->has_name(_name);
            return false;
        }
    };

    ~Hier()
    {
    }

    INLINE Hier& operator << (Hier* ptr_)
    {
        append_child(ptr_);
        return *this;
    }

    INLINE Hier& operator << (_Ref& ref_)
    {
        append_ref(ref_);
        return *this;
    }

    INLINE Hier& operator << (level_switch switch_) const
    {
        return *change_level(switch_);
    }

    INLINE Hier& operator << (const _STD string& name_)
    {
        append_child(new Hier(name_));
        return *this;
    }

};

void test_hier()
{
    Hier::_Ref root(*new Hier("$root"));
    (*root) << "ch0" 
            << "ch1" 
            << Hier::push 
                << "ch2";

    Hier::_Ref child(*new Hier("level1(1)"));
    (*root) << child
            << new Hier("level1(2)" )
            << Hier::push 
               << new Hier("level2(1)" )
            << Hier::pop 
            << new Hier("level1(3)" );
         ;

    Hier::_Ref r2 = root->find_child(Hier::_by_name("level1(3)"));

    //Hier::_Refs path;
    //l2->get_path(path);
    root->clear();
    root.reset();
}
//MIDL_INTERFACE(      "654F7EF5-CFDF-4df9-A450-6C6AA6C60000")
struct __declspec(uuid("654F7EF5-CFDF-4df9-A450-6C6AA6C60000"))
IKnown : public IPersistStreamInit
{
    virtual HRESULT STDMETHODCALLTYPE mymethod( void) = 0;
};

EXTERN_C const IID IID_IKnown;

class   Known : public IKnown
{
protected:
    long    _refs;
public:
    Known()
        : _refs(0)
    {}

    virtual ~Known()
    {
    }
    virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
        /* [in] */ REFIID riid,
        /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
    {
        if (riid == IID_IUnknown)
        {
            *ppvObject = static_cast<IUnknown*>(this);
            AddRef();
        }
        else if (riid == IID_IPersist)
        {
            *ppvObject = static_cast<IPersist*>(this);
            AddRef();
        }
        else if (riid == IID_IPersistStreamInit)
        {
            *ppvObject = static_cast<IPersistStreamInit*>(this);
            AddRef();
        }
        else if (riid == __uuidof(IKnown))
        {
            *ppvObject = static_cast<IKnown*>(this);
            AddRef();
        }
        else 
            return E_NOINTERFACE;
        return S_OK;

    }

    virtual ULONG STDMETHODCALLTYPE AddRef( void)
    {
        return ++_refs;
    }

    virtual ULONG STDMETHODCALLTYPE Release( void)
    {
        if (!--_refs)
        {
            delete this;
            return 0;
        }
        return _refs;
    }
    // IPersist
    virtual HRESULT STDMETHODCALLTYPE GetClassID( 
        /* [out] */ __RPC__out CLSID *pClassID)
    {
        return E_NOTIMPL;
    }
    // IPersistStreamInit
    virtual HRESULT STDMETHODCALLTYPE IsDirty( void)
    {
        return S_FALSE;
    }
    
    virtual HRESULT STDMETHODCALLTYPE Load( 
        /* [in] */ __RPC__in_opt LPSTREAM pStm)
    {
        return E_NOTIMPL;
    }
    
    virtual HRESULT STDMETHODCALLTYPE Save( 
        /* [in] */ __RPC__in_opt LPSTREAM pStm,
        /* [in] */ BOOL fClearDirty)
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE GetSizeMax( 
        /* [out] */ __RPC__out ULARGE_INTEGER *pCbSize)
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE InitNew( void)
    {
        return E_NOTIMPL;
    }

    // IKnown
    virtual HRESULT STDMETHODCALLTYPE mymethod( void)
    {
        return S_OK;
    }

};

_COM_SMARTPTR_TYPEDEF(IKnown, __uuidof(IKnown));

class   Me : public refcounted<Me>
   //, public std::enable_shared_from_this<Me> 
   , public shareable<Me>
{
public:
    int _val;
    Me()
        : _val(0)
    {}

    ~Me()
    {
    }

    virtual void virtfunc()
    {
        return;
    }

    void OnAddRef()
    {
        _val += 2;
    }

    void OnRelease()
    {
        _val -= 1;
    }

    void FinalRelease()
    {
        _val = -_val;
    }
};

class Me2 : public Me
{
public:
    int _val2;
    Me2()
        : Me()
    {}
    ~Me2()
    {
    }
};

typedef sharing<Me> shared;
#import <msxml.tlb>

template<typename _Ty>
long refs(_Ty* ref_)
{
    long ret = 0;
    if (ref_)
    {
        ref_->AddRef();
        ret = ref_->Release();
    }
    return ret;
}

#include <atlbase.h>
void test0()
{
    ::CoInitialize(NULL);
    try
    {
        MSXML::IXMLDOMDocumentPtr doc(__uuidof(MSXML::DOMFreeThreadedDocument));

        //sharing<Me>::strong me0(new Me2());
        //Me2* me1 = dynamic_pointer_cast<Me2>(me0).get()
        //    ,* me2 = dynamic_pointer_cast<Me2>(me0).get()
        //    ,* me3 = dynamic_pointer_cast<Me2>(me0).get()
        //    ,* me4 = dynamic_pointer_cast<Me2>(me0).get()
        //;

        refs(doc.GetInterfacePtr());
        //IUnknownPtr uuu = new Known();
        sharing<IUnknown>::strong sUnk(new Known());
        ATL::CComPtr<IUnknown> spKnown(best_cast<IUnknown>(sUnk.get()));
        //uuu = NULL;
        //IUnknownPtr sUnk(doc.GetInterfacePtr());
        refs(doc.GetInterfacePtr());
        ////doc = NULL;
        sharing<IDispatch>::strong sDisp //(sUnk);
             = dynamic_pointer_cast<IUnknown>(sUnk);
        //IDispatchPtr sDisp = sUnk.get();
        refs(doc.GetInterfacePtr());

        sharing<MSXML::IXMLDOMDocument>::strong sDoc(sUnk);// = dynamic_pointer_cast<IUnknown>(sDisp);
        //MSXML::IXMLDOMDocumentPtr sDoc(sUnk.get());
        refs(doc.GetInterfacePtr());
        IDispatchPtr d = sDoc.get();
        IPersistPtr pi = (IPersist*)best_cast<IPersist>(sDoc.get());
        refs(doc.GetInterfacePtr());
        IUnknownPtr _ = sUnk.get(); 
        IKnownPtr _0 = _; //sUnk.get(); 
        IKnownPtr _00 = sUnk.get();
        IPersistStreamInit
            * _d0 = dynamic_pointer_cast<IPersistStreamInit>(sUnk).get(),
            * _d1 = dynamic_pointer_cast<IPersistStreamInit>(sUnk).get(),
            * _d2 = dynamic_pointer_cast<IPersistStreamInit>(sUnk).get(),
            * _d3 = dynamic_pointer_cast<IPersistStreamInit>(sUnk).get()
            ;
        IKnownPtr _000 = sUnk.get(); //dynamic_pointer_cast<MSXML::IXMLDOMDocument>(sUnk).get();
        IKnownPtr _0000 = _; //sUnk.get(); //dynamic_pointer_cast<MSXML::IXMLDOMDocument>(sUnk).get();

        refs(doc.GetInterfacePtr());
        sharing<IPersistStream>::strong _1(sUnk.get()); //(marus::best_cast<IPersistStream>(sDisp.get()));
        //IPersistStreamPtr _1 = sDisp.GetInterfacePtr();
        refs(doc.GetInterfacePtr());
        if (!marus::com_caster<IPersistStream>::cast(sUnk.get()))
        {
        }
        IPersistStreamInitPtr _2 = sUnk.get();
        refs(doc.GetInterfacePtr());
        HRESULT hr = _2->IsDirty();
        IUnknownPtr _3(sUnk.get());
        refs(doc.GetInterfacePtr());
        //MSXML::IXMLDOMDocumentPtr _4 = marus::best_cast<MSXML::IXMLDOMDocument>(_3.GetInterfacePtr());
        //sharing<MSXML::IXMLDOMDocument>::strong _5(doc.GetInterfacePtr()); // _4 _3 _2 _1 sDoc.get()
        //_5.reset();
        //_5.reset(d.GetInterfacePtr());
        //d = NULL;
        //doc = NULL;
        //MSXML::IXMLDOMImplementationPtr impl;
        //_5->get_implementation(&impl);
        //impl = doc->implementation;
        sUnk.reset();
        refs(doc.GetInterfacePtr());
            //marus::best_cast<MSXML::IXMLDOMDocument>(sDisp.get());
        d = 0;
        refs(doc.GetInterfacePtr());
        refs(_0.GetInterfacePtr());
        _0 = 0;
        refs(doc.GetInterfacePtr());
        doc = 0;
        //_4 = 0;
        _3 = 0;
        _2 = 0;
    }
    catch(...)
    {
    }
    ::CoUninitialize();

}
typedef sharing<Me> shared;

void  test_enable_shared() {
   Me* p = new Me();
   shared::strong spMe(p);
   shared::strong me0 =    p->SharedRef();

   shared::strong me2(p);

   me0.reset(p);

}

int _tmain(int argc, _TCHAR* argv[])
{
   test_enable_shared();
    test_hier();
    //return 0;
    test0();
    

    shared::strong me0;
    me0.reset(new Me());
    //me0.reset();

    shared::weak wme0 = me0;
    shared::strong me1(wme0);
    wme0.reset();
    //SmartPtr<Me> spMe;
    //if (!spMe)
    //{
    //    spMe = new Me();
    //    if (spMe)
    //        spMe = NULL;
    //    if (spMe == NULL)
    //        spMe = new Me();
    //    if (spMe != NULL)
    //        spMe = NULL;
    //}
    //Reference<Me> me(new Me());
    //WeakRef<Me> wme = me;
    //sharing<Me>::strong me2 = wme.lock();
    //swap(me, me2);
    //me2->_val = 111;
    ////me.reset();
    ////me2 = wme.lock();
    //
    sharing<char>::strong sz(new char[10]);
    sz.reset();

    //me2.reset();
    _STD vector< shared::weak > vme;
    vme.push_back(wme0);
    vme.push_back(wme0);
    vme.push_back(wme0);
    vme.push_back(wme0);
    vme.push_back(wme0);
    vme.push_back(wme0);
    //me0.reset();
    shared::weak r = vme[2];
    if (r.expired())
    {
    }
    shared::strong sr(r); //vme[2]);
    me0 = vme[2].lock();
    me1 = me0;
    if (!sr)
    {
    }
    if (sr)
    {
    }
    if (sr != NULL)
    {
    }
    if (sr == NULL)
    {
    }
    //me2.reset();
    vme.clear();
 //   atomic_long l = 0;
 //   ++l;
 //   l--;
 //   if (__is_on_stack(&l))
 //       l += 100;
 //   l -= 50;
 //   long t = -2;
 //   if (interlocked32::increment_ne<-1>(t))
 //       l += t;
 //   Me* me = new Me();
 //   me->AddRef();
 //   me->Release();
 //   __int64 i64 = 0;
 //   ::InterlockedExchangeAdd64(&i64, 100);
 //   ::InterlockedIncrement64(&i64);
 //   ::InterlockedDecrement64(&i64);
 //   ::InterlockedCompareExchange64(&i64, 200, 100);
 //   ::InterlockedOr64(&i64, 1);
 //   ::InterlockedAnd64(&i64, 0x55);
 //   ::InterlockedXor64(&i64, 0x55);

 //   float f = 1.5;
 //   interlocked<4>::set(f, (float)2.7);
 //   float f2 = 1.5f - interlocked<4>::get(f);
 //   interlocked<4>::compare_exchange(f, (float)2.7, f2);

	//return l;
}

